package com.kovidinvo.domofon.utils

import com.kovidinvo.domofon.data.ShortPlaceUrl
import com.kovidinvo.domofon.data.ShortPlaceUrlRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.http.server.reactive.ServerHttpResponse
import org.springframework.stereotype.Component
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RestController
import reactor.core.publisher.Mono
import java.net.URI
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.util.concurrent.atomic.AtomicLong
import kotlin.jvm.optionals.getOrNull

internal class TinyUrl {
    private val alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"
    private val base = alphabet.length

    fun encode(num: Long) : String {
        if(num==0L) return alphabet[0].toString()
        var res = ""
        var num = num
        while(num>0) {
            res+=alphabet[(num % base).toInt()]
            num /= base
        }
        return res.reversed()
    }

    fun decode(code : String) : Long {
        var num = 0L
        for(c in code.toList()) {
            num = (num*base) + alphabet.indexOf(c)
        }
        return num
    }
}

@Component
class UrlShortener {
    private var currentId  = AtomicLong(LocalDateTime.now().toEpochSecond(ZoneOffset.UTC)*1000)

    @Autowired
    lateinit var repo : ShortPlaceUrlRepository

    private val tinyUrl = TinyUrl()

    fun getShortUrlCode(url:String) : String {
        val code = currentId.getAndIncrement()
        val link = tinyUrl.encode(code)
        repo.insert(ShortPlaceUrl(code,url,""))
        return link
    }

    fun getLongUrlByCode(code:Long) : String? {
        val shorturl = repo.findById(code)
        if(shorturl.isEmpty) return null
        return shorturl.get().url
    }


}

@RestController
class ShortUrlRedirect {
    @Autowired
    lateinit var shortener : UrlShortener
    private val tinyUrl = TinyUrl()

    @GetMapping("/tinyurl/{link}")
    fun redirectLink(@PathVariable link:String, resp : ServerHttpResponse) : Mono<Void> {
        if(link.length>12) return resp.apply { setStatusCode(HttpStatus.BAD_REQUEST) }.setComplete()
        val code = tinyUrl.decode(link)
        val shorturl = shortener.getLongUrlByCode(code) ?: return resp.apply { setStatusCode(HttpStatus.NOT_FOUND) }.setComplete()
        return resp.apply {
            setStatusCode(HttpStatus.PERMANENT_REDIRECT)
            headers.location= URI.create(shorturl)
        }.setComplete()
    }
}